import { chain } from 'youwilllike'
import { methodsInfoTypes } from '../../types/class'
import { FunctionTypes } from '../../types/func'
import { fileTypeBase } from '../../types/generate'
import { ASTResult, Options } from '../../types/ops'
import { methodDescription } from '../../utils/class'
import { retSubFaceValue } from '../../utils/classReturn'
import { getParams } from '../../utils/common'
import { getDesc } from '../../utils/func'
import { mergeReturndoc, subFaceValue } from '../../utils/funcReturn'
import { GenerateGrammar } from './generateGrammar'
/**
 * @description GenerateBase
 * @related GenerateBase
 */
export class GenerateBase extends GenerateGrammar {
  content: ASTResult[] | []
  opts: Options | {}
  constructor(content: ASTResult[], opts: Options) {
    super()
    this.content = content
    this.opts = opts
  }
  /**
   * @description 换行
   * @param { string } lineContent
   */
  protected wrap(lineContent: string): string {
    return (lineContent += '\n')
  }
  /**
   * @description 生成方法名
   * @param { ASTResult } contentItem
   * @returns { string }
   */
  generateMethodName(contentItem: ASTResult): fileTypeBase['methodName'] {
    // ### `function name` \n
    return this.wrap('### `' + `${contentItem.type} ${contentItem.name}` + '`')
  }
  /**
   * @description 生成注释 func 和 class的顶部注释
   * @param contentItem
   */
  generateDesc(contentItem: ASTResult) {
    const desc = getDesc(contentItem)
    if (!desc) return ''
    return this.wrap(`#### Description`) + this.wrap(`${desc}`)
  }

  /**
   * @description 生成参数
   * @param { ASTResult } contentItem
   * @returns { string }
   */
  generateArguments(contentItem: ASTResult): fileTypeBase['arguments'] {
    const paramsContent = getParams(contentItem)
      ?.map(params => {
        return this.wrap(`- ${params.name}:${params.type}`)
      })
      ?.join(' ')
    return this.wrap('#### Arguments') + this.wrap(paramsContent || '')
  }
  /**
   * @description 生成实例
   */
  generateExample(contentItem: ASTResult): fileTypeBase['example'] {
    const doc = contentItem.doc
    if (!doc) return ''
    const example = doc.tags.find(docItem => docItem.title === 'example')
    if (!example) return ''
    return this.wrap('#### Example') + this.wrap('```ts\n' + example.description + '\n```\n')
  }

  generateFuncReturns(contentItem: ASTResult): string {
    if (contentItem.type !== 'function') {
      return ''
    }
    const funcReturn = new chain.ChainOfResponsibility(subFaceValue).addChain(mergeReturndoc)
    const returnResule = this.wrap(funcReturn.dispatch(contentItem) as string)
    return this.wrap('#### Returns') + returnResule
  }

  generateClassReturn(contentItem: ASTResult) {
    if (contentItem.type !== 'class') return ''
    const methodListStr = contentItem.methodsInfo.map((method: methodsInfoTypes) => {
      //TODO: method params not readme
      const classReturn = new chain.ChainOfResponsibility(retSubFaceValue).addChain(mergeReturndoc)
      const paramsContent = getParams(method as FunctionTypes)
        ?.map(params => {
          return this.wrap(`${params.name}: ${params.type}`)
        })
        ?.join(' ')
      return this.wrap(`- ${method.name}(${paramsContent}):  ${classReturn.dispatch(method)}  ${methodDescription(method)} `)
    })
    return this.wrap(`#### method`) + methodListStr.join(' ')
  }
  /**
   * @description 生成
   * @param contentItem
   */
  protected generate(content: ASTResult) {
    return this.generateMethodName(content) + this.generateDesc(content) + this.generateArguments(content) + this.generateExample(content) + this.generateFuncReturns(content) + this.generateClassReturn(content)
  }
  /**
   * @description 生成中标题
   */
  generateHeadline(title: string): string {
    return this.wrap(`### \`${title}\``)
  }

  protected toLink(contentItem: ASTResult, URL: string) {
    return this.wrap(`[\`${contentItem.name}\`](${URL})`)
  }

  protected eliminateRedundancy(): ASTResult[] {
    // [
    //   {
    //     type: 'function',
    //     name: 'A',
    //     params: [ [Object], [Object] ],
    //     return: 'any',
    //     doc: { description: '', tags: [Array] }
    //   },
    //   {
    //     type: 'class',
    //     name: 'B',
    //     constructorInfo: { params: [Array] },
    //     methodsInfo: [ [Object] ],
    //     propertiesInfo: [ [Object] ],
    //     doc: { description: '', tags: [Array] }
    //   },
    //   {
    //     type: 'function', 这是class B的constructor 需要剔除掉
    //     name: 'B',
    //     params: [ [Object] ],
    //     return: 'any',
    //     doc: undefined
    //   }
    // ]
    const newContent: ASTResult[] = []
    this.content.map(item => {
      const listContent = newContent.find(content => content.name === item.name)
      if (!listContent) {
        // 如果如果没有name相同的函数在数组中就推入
        newContent.push(item)
        return
      }
      // 判断class中的constructor函数是否存在this.content数组中并且type为function
      if (item.type !== listContent.type) {
        const listParams = getParams(listContent)
        const itemParams = getParams(item)
        // class 和 func 的参数是否相等
        const b = JSON.stringify(itemParams) === JSON.stringify(listParams)
        if (!b) {
          newContent.push(item)
        }
      }
    })
    return newContent
  }
}
